package com.drinks.yiniang.ui.widget.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.support.v7.widget.AppCompatTextView;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.drinks.yiniang.R;
import com.hansen.library.listener.CheckDoubleClickListener;
import com.hansen.library.utils.LogUtils;
import com.hansen.library.utils.ScreenSizeUtils;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * @author han
 * @date 2019/12/23
 */
public class RandomDragTagView extends ViewGroup implements Serializable {

    private AppCompatTextView mTagTextView;

    private BreathingTagView mBreathingTagView;

    private final int mLinkLineWidth, mBreathSize;
    private final int dp10, dp24;

    private Map<View, Rect> mViewBoundCache = new HashMap<>();//save all children's bound, save in onLayout

    private Paint mPaint;
    private Path mPath;

    private Rect mChildBreathRect;
    private Rect mChildTagRect;

    // 是否多跟手指按下
    private boolean mPointerDown = false;
    //返回值是int类型，其含义是一段滑动的距离，一般用在解决滑动冲突上，用法就是获取手指滑动的距离为X，
    //如果X大于这个值就让控件去处理滑动事件，否则就不作滑动处理。
    private int mTouchSlop = -1;
    //是否显示在左侧
    private boolean isShowLeft;
    //开始拖动
    private boolean mStartDrag = false;
    // 是否可以拖拽
    private boolean mCanDrag = true;
    // 是否可以拖拽出父控件区域(为true时父控件添加android:clipChildren="false")
    private boolean mDragOutParent = false;

    private float mStrokeWidth = 3f;
    private float mLastMotionRawY;
    private float mLastMotionRawX;

    // 最小挤压到宽度(文字+线条+呼吸灯=屏幕一半宽度)
    private int mMinExtrusionWidth;

    // 文本圆角矩形的最大宽度
    private final int mMaxTextViewWidth;
    private int mCurrentTextViewWidth;

    private OnTagDragChangeListener onTagDragChangeListener;

    public RandomDragTagView(Context context) {
        this(context, null);
    }

    public RandomDragTagView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RandomDragTagView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        dp10 = ScreenSizeUtils.dp2px(context, 10);
        dp24 = ScreenSizeUtils.dp2px(context, 24);

        mBreathSize = ScreenSizeUtils.dp2px(context, 12);
        mLinkLineWidth = ScreenSizeUtils.dp2px(context, 12);
        mMinExtrusionWidth = ScreenSizeUtils.getWidth(context) / 2 - mLinkLineWidth - mBreathSize;
        mCurrentTextViewWidth = mMaxTextViewWidth = ScreenSizeUtils.getWidth(context) * 2 / 3;

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setColor(Color.WHITE);
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setAntiAlias(true);

        mPath = new Path();

        setWillNotDraw(false);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (getChildCount() != 2) {
            return;
        }

        int wholeWidth = mLinkLineWidth;
        int wholeHeight = 0;

        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);

            // measure
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            wholeWidth += child.getMeasuredWidth();

            wholeHeight = Math.max(wholeHeight, child.getMeasuredHeight());
        }

        setMeasuredDimension(resolveSize(wholeWidth, widthMeasureSpec),
                resolveSize(wholeHeight, heightMeasureSpec));
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (getChildCount() != 2) {
            return;
        }

        int lengthX = 0;
        int lengthY = 0;

        View child;
        int childWidth, childHeight;

        if(isShowLeft) {
            //第二个view
            child = this.getChildAt(1);

            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            lengthX += childWidth;
            lengthY += childHeight;

            child.layout(lengthX - childWidth, lengthY - childHeight, lengthX, lengthY);

            //第一个view
            child = this.getChildAt(0);

            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            lengthX += mLinkLineWidth + childWidth;
            lengthY = (lengthY + childHeight) / 2;

            child.layout(lengthX - childWidth, lengthY - childHeight, lengthX, lengthY);
        } else {
            //第一个view
            child = this.getChildAt(0);

            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            lengthX += childWidth;
            lengthY = (getMeasuredHeight() + childHeight) / 2;

            child.layout(lengthX - childWidth, lengthY - childHeight, lengthX, lengthY);

            //第二个view
            child = this.getChildAt(1);

            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            lengthX += mLinkLineWidth + childWidth;
            lengthY = childHeight;

            child.layout(lengthX - childWidth, lengthY - childHeight, lengthX, lengthY);
        }

        captureChildrenBound(mBreathingTagView);
        captureChildrenBound(mTagTextView);
    }

    private void captureChildrenBound(View childView) {
        //save child bound
        Rect rect = mViewBoundCache.get(childView);

        if (rect == null) {
            rect = new Rect();
            mViewBoundCache.put(childView, rect);
        }
        rect.left = childView.getLeft();
        rect.top = childView.getTop();
        rect.right = childView.getRight();
        rect.bottom = childView.getBottom();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if(getChildCount() != 2) {
            return;
        }

        mChildBreathRect = mViewBoundCache.get(mBreathingTagView);
        mChildTagRect = mViewBoundCache.get(mTagTextView);

        if(mChildBreathRect == null || mChildTagRect == null) {
            return;
        }

        mPath.reset();
        canvas.save();

        float y = (mChildTagRect.bottom - mChildTagRect.top) / 2;

        if(isShowLeft) {
            mPath.moveTo(mChildTagRect.right, y);
            mPath.lineTo(mChildTagRect.right + mLinkLineWidth + (mChildBreathRect.right - mChildBreathRect.left) / 2 - mBreathingTagView.getInnerSize() / 2, y);
        } else {
            mPath.moveTo((mChildBreathRect.right - mChildBreathRect.left) / 2 + mBreathingTagView.getInnerSize() / 2, y);
            mPath.lineTo(mChildTagRect.left, y);
        }

        canvas.drawPath(mPath, mPaint);
        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mTouchSlop < 0) {
            mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        }
        if (!canDragView()) return super.onTouchEvent(event);
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                float x = event.getRawX();
                float y = event.getRawY();
                getParent().requestDisallowInterceptTouchEvent(true);

                mStartDrag = false;
                mPointerDown = false;
                mLastMotionRawX = x;
                mLastMotionRawY = y;

                // 调整索引 位于其他标签之上
                //moveToTop(this);
                this.bringToFront();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mPointerDown = true;
                break;
            case MotionEvent.ACTION_MOVE:
                float rawX = event.getRawX();
                float rawY = event.getRawY();

                if (!mStartDrag) {
                    mStartDrag = true;
//                    if (mDragListener != null) {
//                        mDragListener.onStartDrag();
//                    }
                }
                if (!mPointerDown) {
                    float xDiff = rawX - mLastMotionRawX;
                    float yDiff = rawY - mLastMotionRawY;

                    // 处理move事件
                    handlerMoveEvent(xDiff, yDiff);
                    mLastMotionRawY = rawY;
                    mLastMotionRawX = rawX;
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mPointerDown = false;
                break;
            // case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                mPointerDown = false;
                mStartDrag = false;
                getParent().requestDisallowInterceptTouchEvent(false);

                final float translationY = getTranslationY();
                final int parentHeight = ((View) getParent()).getHeight();
//                if (mMaxParentHeight - mDeleteRegionHeight < translationY) {
//                    removeTagView();
//                } else if (parentHeight - getHeight() < translationY) {
//                    startReBoundAnimator();
//                }
//
                if (onTagDragChangeListener != null) {
                    onTagDragChangeListener.onTagDragChange(this, isShowLeft ? getTranslationX() + getWidth() : getX(), getY(), isShowLeft);
                }

                break;
        }
        return true;
    }

    /**
     * 处理手势的move事件
     *
     * @param xDiff x轴方向的偏移量
     * @param yDiff y轴方向的偏移量
     */
    private void handlerMoveEvent(float xDiff, float yDiff) {
        float translationX = getTranslationX() + xDiff;
        float translationY = getTranslationY() + yDiff;

        // 越界处理 最大最小原则
        int parentWidth = ((View) getParent()).getWidth();
        int parentHeight = ((View) getParent()).getHeight();

        // 分情况处理越界 宽度
        if (translationX <= 0) {
            translationX = 0;
            // 标签文本出现挤压效果
            if (isShowLeft) {
                extrusionTextRegion(xDiff);
            }
        } else if (translationX >= parentWidth - getWidth()) {
            translationX = parentWidth - getWidth();
            // 右侧挤压
            if (!isShowLeft) {
                extrusionTextRegion(-xDiff);
                handleWidthError();
            }
        } else {
            int textWidth = mTagTextView.getWidth();

            if (isShowLeft) {// 左侧视图
                if (getTranslationX() == 0 && textWidth >= mMinExtrusionWidth && textWidth < mCurrentTextViewWidth) {
                    translationX = 0;
                    extrusionTextRegion(xDiff);
                }
            } else {//右侧
                if (textWidth >= mMinExtrusionWidth && textWidth < mCurrentTextViewWidth) {
                    extrusionTextRegion(-xDiff);
                    handleWidthError();
                }
            }
        }

        // 高度越界处理
        if (translationY <= 0) {
            translationY = 0;
        } else if (translationY >= parentHeight - getHeight()) {
            translationY = parentHeight - getHeight();
        }

        setTranslationX(translationX);
        setTranslationY(translationY);
    }

    // 处理宽度误差
    private void handleWidthError() {
        post(new Runnable() {
            @Override
            public void run() {
                if (getParent() == null) return;
                int parentWidth = ((View) getParent()).getWidth();
                int maxWidth = parentWidth - getWidth();
                setTranslationX(maxWidth);
            }
        });
    }

    /**
     * 挤压拉伸文本区域
     *
     * @param deltaX 偏移量
     */
    private void extrusionTextRegion(float deltaX) {
        int textWidth = mTagTextView.getWidth();

        ViewGroup.LayoutParams lp = mTagTextView.getLayoutParams();

        if (textWidth >= mMinExtrusionWidth) {
            lp.width = (int) (textWidth + deltaX);
            // 越界判定
            if (lp.width <= mMinExtrusionWidth) {
                lp.width = mMinExtrusionWidth;
            } else if (lp.width >= mMaxTextViewWidth) {
                lp.width = mMaxTextViewWidth;
            }

            mTagTextView.setLayoutParams(lp);
        }
    }

    /**
     * 添加标签
     *
     * @param text           标签文本
     * @param x              相对于父控件的x坐标百分比
     * @param y              相对于父控件的y坐标百分比
     * @param isLeft 是否显示左侧标签
     */
    public void initTagView(final float x, final float y, String text, boolean isLeft) {
        setVisibility(INVISIBLE);

        isShowLeft = isLeft;

        LayoutParams paramsBreath = new LayoutParams(mBreathSize, mBreathSize);
        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, dp24);

        mBreathingTagView = new BreathingTagView(getContext());
        mTagTextView = new AppCompatTextView(getContext());

        mTagTextView.setMaxWidth(mMaxTextViewWidth);
        mTagTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
        mTagTextView.setTextColor(Color.WHITE);
        mTagTextView.setPadding(dp10, 0, dp10, 0);
        mTagTextView.setGravity(Gravity.CENTER);
        mTagTextView.setLines(1);
        mTagTextView.setEllipsize(TextUtils.TruncateAt.END);
        mTagTextView.setBackgroundResource(R.drawable.shape_bkg_drag_tag);
        mTagTextView.setText(text);

        mBreathingTagView.startBreathingAnimator();
        mBreathingTagView.setOnClickListener(new CheckDoubleClickListener() {
            @Override
            public void onCheckDoubleClick(View v) {
                switchTagDirection();
            }
        });

        addView(mBreathingTagView, paramsBreath);
        addView(mTagTextView, params);

        post(new Runnable() {
            @Override
            public void run() {
                // 边界检测
                mCurrentTextViewWidth = Math.min(getWidth() - mBreathSize - mLinkLineWidth, mMaxTextViewWidth);

                setViewPosition(x, y);

                if (onTagDragChangeListener != null) {
                    onTagDragChangeListener.onTagDragChange(RandomDragTagView.this, isShowLeft ? getTranslationX() + getWidth() : getX(), getY(), isShowLeft);
                }
            }
        });
    }

    //初始设置tag位置，默认在右边
    //右边宽度不够先判断挤压tag textview宽度能否存放，能则挤压
    //挤压到最小挤压宽度还是不能放在右边时更换到左边边并根据宽度挤压tag textview)
    private void setViewPosition(float translationX, float translationY) {
        //父控件的宽高
        int parentWidth = ((View) getParent()).getWidth();
        int parentHeight = ((View) getParent()).getHeight();
        int textWidth = mTagTextView.getWidth();

        boolean isNeedSwitch = false;

        translationX = translationX < 0 ? 0 : translationX > parentWidth ? parentWidth - getWidth() : translationX;
        translationY = translationY < 0 ? 0 : translationY > parentHeight - getHeight() ? parentHeight - getHeight() : translationY;

        if(!isShowLeft) {//tag在右边
            if(translationX > parentWidth - getWidth()) {//右边越界
                float offsetX = getWidth() - (parentWidth - translationX);
                if(textWidth - offsetX >= mMinExtrusionWidth) {
                    extrusionTextRegion(-offsetX);
                } else {//无法挤压，换边
                    isNeedSwitch = true;
                }
            }
        } else {//tag在左边
            translationX = translationX - getWidth();

            if(translationX < 0) {//左边越界
                if(textWidth + translationX >= mMinExtrusionWidth) {
                    extrusionTextRegion(translationX);
                    translationX = 0;
                } else {//无法挤压，换边
                    isNeedSwitch = true;
                }
            }
        }

        setTranslationX(translationX);
        setTranslationY(translationY);

        setVisibility(VISIBLE);

        if(isNeedSwitch) {
            switchTagDirection();
        }
    }

    private void switchTagDirection() {
        isShowLeft = !isShowLeft;

        float translationX, translationY;

        requestLayout();

        if (isShowLeft) {
            translationX = getTranslationX() - getWidth() + mBreathingTagView.getWidth();
        } else {
            translationX = getTranslationX() + getWidth() - mBreathingTagView.getWidth();
        }

        translationY = getTranslationY();

        // 边界检测
        // 越界的情况下 改变textLayout 的高度
        int parentWidth = ((View) getParent()).getWidth();
        int parentHeight = ((View) getParent()).getHeight();
        int textWidth = mTagTextView.getWidth();

        if (translationX <= 0) {//左边越界
            extrusionTextRegion(translationX);
            translationX = 0;
        } else if (translationX >= (parentWidth - getWidth())) {//右边越界
            float offsetX = getWidth() - (parentWidth - translationX);
            if(textWidth < mMinExtrusionWidth) {
                translationX -= offsetX;
            } else if(textWidth - offsetX < mMinExtrusionWidth) {//无法挤压，向左侧移位
                translationX -= mMinExtrusionWidth - (textWidth - offsetX);
            }
            extrusionTextRegion(-offsetX);
        }

        translationY = translationY < 0 ? 0 : translationY > parentHeight - getHeight() ? parentHeight - getHeight() : translationY;

        setTranslationX(translationX);
        setTranslationY(translationY);
    }

    // 是否可以拖拽
    public boolean canDragView() {
        return mCanDrag;
    }

    public void setCanDrag(boolean canDrag) {
        this.mCanDrag = canDrag;
    }

    public boolean isShowLeft() {
        return isShowLeft;
    }

    public float getPercentTransX() {
        int parentWidth = ((View) getParent()).getWidth();
        return getTranslationX() / parentWidth;
    }

    public float getPercentTransY() {
        int parentHeight = ((View) getParent()).getHeight();
        return getTranslationY() / parentHeight;
    }

    public void setOnTagDragChangeListener(OnTagDragChangeListener onTagDragChangeListener) {
        this.onTagDragChangeListener = onTagDragChangeListener;
    }

    public interface OnTagDragChangeListener {
        void onTagDragChange(RandomDragTagView tagView, float x, float y, boolean isLeft);
    }
}
